#pragma once

#include <libusb.h>

#define     ARTO_USB_EXIT_LEN       0x0
#define     ARTO_USB_EXIT_ADDR      0x0

#define     ARTO_USB_MAGIC_NUM_0    'U'
#define     ARTO_USB_MAGIC_NUM_1    'S'
;
#pragma pack(push)
#pragma pack(1)
typedef struct
{
    unsigned short  port_index;
    unsigned short  header_len;
    unsigned int    data_len;
    unsigned char   status;
    unsigned char   reserved[3];
}STRU_HID_HEADER;

typedef struct
{
    unsigned char   magic_num[8];
    unsigned int    header_len;
    unsigned int    total_len;
    unsigned int    payload_len;
    unsigned int    fragment_num;
    unsigned int    fragment_idx;
    unsigned char   sub_proto;
    unsigned char   reserved[3];
    unsigned int    checksum;
}STRU_USB_HEADER;

typedef struct
{
    unsigned int    cur_len;
    unsigned int    fragment_idx;
    unsigned short  port_index;
    unsigned short  header_len;
    unsigned int    data_len;
}STRU_USB_FRAGMENT_INFO;

#pragma pack(pop)

class ar_usb
{
public:
    ar_usb();
    ~ar_usb();

    int usb_print_dev_list();
    libusb_device_handle * usb_open_by_index(unsigned int index);
    int usb_class_configure(libusb_device_handle* handle, unsigned int index);
    int usb_close_dev(libusb_device_handle * handle);
    int usb_reset_dev(libusb_device_handle * handle);

    int usb_transfer_data_with_addr_romcode(libusb_device_handle * handle, unsigned long long addr, unsigned char* data, unsigned int len, unsigned int timeout);
    int usb_exit_romcode(libusb_device_handle* handle, unsigned int timeout);

    int usb_find_class_interface(struct libusb_config_descriptor* conf_desc, int nb_ifaces,
        libusb_class_code class_id,
        uint8_t* endpoint_in,
        uint8_t* endpoint_out,
        uint32_t* endpoint_in_size,
        uint32_t* endpoint_out_size);
    unsigned int usb_get_checksum(unsigned char* data, unsigned int len);
    int usb_magic_num_check(unsigned char* data);
    int usb_hid_write(libusb_device_handle * handle, unsigned char* data, 
                        unsigned int buf_len, unsigned int timeout);
    int usb_hid_read(libusb_device_handle* handle, unsigned char* data,
        unsigned int buf_len, unsigned int timeout);

    //int usb_hid_send_data(libusb_device_handle* handle, unsigned char* data, 
    //                    unsigned int buf_len, unsigned int timeout);
    //unsigned char * usb_hid_recv_data(libusb_device_handle* handle, 
    //                    unsigned int* recv_len, unsigned int timeout);
    //unsigned char * usb_hid_get_send_buffer(unsigned int buf_len, unsigned int port);

    //int usb_transfer_data_rtos(libusb_device_handle * handle, unsigned int index, 
    //                            unsigned char* data, unsigned int len, unsigned int timeout);
    //unsigned char * usb_recv_data_rtos(libusb_device_handle * handle, unsigned int index,
    //                            unsigned int * recv_len, unsigned int timeout);
    
    

private:
    libusb_device           ** devs;
    ssize_t                 dev_cnt;
    
    uint8_t                 hid_endpoint_in;
    uint8_t                 hid_endpoint_out;
    uint32_t                hid_endpoint_in_max_size;
    uint32_t                hid_endpoint_out_max_size;
    STRU_USB_FRAGMENT_INFO  fragment_info;

    int print_one_dev_list(libusb_device* dev, int index);
};
